﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// 
    /// </summary>
    public enum EXPERIMENTAL1
    {
        /// <summary>
        /// 
        /// </summary>
        MUL,
        /// <summary>
        /// 
        /// </summary>
        R,
        /// <summary>
        /// 
        /// </summary>
        G,
        /// <summary>
        /// 
        /// </summary>
        B,
        /// <summary>
        /// 
        /// </summary>
        A,
        /// <summary>
        /// 
        /// </summary>
        SUM,
        /// <summary>
        /// 
        /// </summary>
        BRIGHTNESS,
        /// <summary>
        /// 
        /// </summary>
        LUMINANCE,
        /// <summary>
        /// 
        /// </summary>
        GRAYVALUE,
        /// <summary>
        /// 
        /// </summary>
        HUE,
        /// <summary>
        /// 
        /// </summary>
        SATURATION,
        /// <summary>
        /// 
        /// </summary>
        DEFAULT,
        /// <summary>
        /// 
        /// </summary>
        TOARGB,
        /// <summary>
        /// 
        /// </summary>
        CHANNELSUM
    }

    /// <summary>
    /// 
    /// </summary>
    public enum RESULT
    {
        /// <summary>
        /// 
        /// </summary>
        GREATER,
        /// <summary>
        /// 
        /// </summary>
        GREATER_OR_EQUAL,
        /// <summary>
        /// 
        /// </summary>
        LESS,
        /// <summary>
        /// 
        /// </summary>
        LESS_OR_EQUAL,
        /// <summary>
        /// 
        /// </summary>
        EQUAL
    }

    /// <summary>
    /// 
    /// </summary>
    public enum COMPARISON_MODE
    {
        /// <summary>
        /// 
        /// </summary>
        DEFAULT,
        /// <summary>
        /// 
        /// </summary>
        ALTERNATIVE
    }

    /// <summary>
    /// With the default constructor (SUM, DEFAULT, GREATER_OR_EQUAL, 40) this is a not that bad edge filter. ;-)
    /// </summary>
    public class Experimental1 : BaseForeBackgroundColorFilter
    {
        private int m_nTolerance = 40;
        protected EXPERIMENTAL1 M_EXPERIMENTAL1 = EXPERIMENTAL1.MUL;
        protected RESULT M_RESULT = RESULT.GREATER_OR_EQUAL;
        protected COMPARISON_MODE M_COMPARISON_MODE = COMPARISON_MODE.DEFAULT;
        protected Dictionary<EXPERIMENTAL1, ColorCalculation> m_aDict = new Dictionary<EXPERIMENTAL1, ColorCalculation>();

        /// <summary>
        /// Gets or sets tolerance
        /// </summary>
        public int Tolerance
        {
            get { return m_nTolerance; }
            set { m_nTolerance = value; }
        }

        /// <summary>
        /// Gets or sets experimental mode
        /// </summary>
        public EXPERIMENTAL1 ExperimentalMode
        {
            get { return M_EXPERIMENTAL1; }
            set { M_EXPERIMENTAL1 = value; }
        }

        /// <summary>
        /// Gets or sets comparison mode
        /// </summary>
        public COMPARISON_MODE ComparisonMode
        {
            get { return M_COMPARISON_MODE; }
            set { M_COMPARISON_MODE = value; }
        }

        /// <summary>
        /// Gets or sets result
        /// </summary>
        public RESULT Result
        {
            get { return M_RESULT; }
            set { M_RESULT = value; }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Experimental1"/> class.
        /// </summary>
        public Experimental1()
            : this(EXPERIMENTAL1.SUM, COMPARISON_MODE.DEFAULT, RESULT.GREATER_OR_EQUAL, 40)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Experimental1"/> class.
        /// </summary>
        /// <param name="_experimental1">The _experimental1.</param>
        internal Experimental1(Experimental1 _experimental1)
        {
            this.M_EXPERIMENTAL1 = _experimental1.M_EXPERIMENTAL1;
            this.M_COMPARISON_MODE = _experimental1.M_COMPARISON_MODE;
            this.M_RESULT = _experimental1.M_RESULT;
            this.m_nTolerance = _experimental1.m_nTolerance;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="_experimental1"></param>
        /// <param name="_comparison_mode"></param>
        /// <param name="_result"></param>
        /// <param name="_nTolerance"></param>
        public Experimental1(EXPERIMENTAL1 _experimental1,COMPARISON_MODE _comparison_mode, RESULT _result, int _nTolerance)
        {
            M_EXPERIMENTAL1 = _experimental1;
            M_RESULT = _result;
            M_COMPARISON_MODE = _comparison_mode;
            m_nTolerance = _nTolerance;

            m_aDict.Add(EXPERIMENTAL1.R, new ColorCalculation(Definitions.GetR));
            m_aDict.Add(EXPERIMENTAL1.G, new ColorCalculation(Definitions.GetG));
            m_aDict.Add(EXPERIMENTAL1.B, new ColorCalculation(Definitions.GetB));
            m_aDict.Add(EXPERIMENTAL1.SATURATION, new ColorCalculation(Definitions.GetSaturation));
            m_aDict.Add(EXPERIMENTAL1.BRIGHTNESS, new ColorCalculation(Definitions.GetBrightness));
            m_aDict.Add(EXPERIMENTAL1.HUE, new ColorCalculation(Definitions.GetHue));
            m_aDict.Add(EXPERIMENTAL1.LUMINANCE, new ColorCalculation(Definitions.GetLuminance));
            m_aDict.Add(EXPERIMENTAL1.MUL, new ColorCalculation(Definitions.GetMul));
            m_aDict.Add(EXPERIMENTAL1.SUM, new ColorCalculation(Definitions.GetSumRGB));
        }

        /// <summary>
        /// Executes this filter
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmapCloned = new UnsafeBitmap((UnsafeBitmap)_bitmap.Clone());
            UnsafeBitmap bitmap = _bitmap;

            Color color = Color.Transparent;
            Color colorEnvironment = Color.Transparent;
            bitmap.Clear(m_ColorBackground);

            ColorCalculation calculation = m_aDict[M_EXPERIMENTAL1];

            int nWidth = bitmap.Width;
            int nHeight = bitmap.Height;

            for (int y = 0; y < nHeight; y++)
            {
                for (int x = 0; x < nWidth; x++)
                {
                    color = bitmapCloned.GetPixel(x, y);

                    int nX = 0;
                    int nY = 0;
                    foreach (Point ptPoint in Definitions.EnvironmentPointListClockwise)
                    {
                        nX = x + ptPoint.X;
                        nY = y + ptPoint.Y;
                        if (nX < nWidth - 1 && nY < nHeight - 1 && nX > -1 && nY > -1)
                        {
                            colorEnvironment = bitmapCloned.GetPixel(nX, nY);
                            float fColor = calculation(color);
                            float fColorEnvironment = calculation(colorEnvironment);

                            if (M_COMPARISON_MODE == COMPARISON_MODE.DEFAULT)
                            {
                                if (color.R > colorEnvironment.R 
                                    && color.G > colorEnvironment.G 
                                    && color.B > colorEnvironment.B 
                                    && Math.Abs(calculation(color) - calculation(colorEnvironment)) > m_nTolerance
                                )
                                {
                                    bitmap.SetPixel(x, y, m_ColorForeground); //Definitions.White
                                }
                            }
                            else
                            {
                                if (fColorEnvironment >= fColor && Math.Abs(fColor-fColorEnvironment)>m_nTolerance)
                                {
                                    bitmap.SetPixel(x, y, m_ColorForeground); //Definitions.White
                                }
                            }
                        }
                    }
                }
            }
            bitmapCloned.Dispose();
            return _bitmap;
        }

        /// <summary>
        /// Used to create a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Experimental1(this);
        }
    }
}
